#include "drv_led_sw.h"
#include "stdio.h"

typedef struct
{
    uint8_t last_level;
    uint8_t current_level;
    uint16_t low_count;
    uint8_t short_press_flag;
    uint8_t long_press_flag;
}sw_infor_t;

static sw_infor_t sw_infor_arr[3];



static void _TIM_NVIC_Initialize(IRQn_Type IRQ_number, FunctionalState command)
{
    NVIC_InitType NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = IRQ_number;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    
    if(ENABLE == command)
    {
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    }
    else
    {
        NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
    }
    
    NVIC_Initializes(&NVIC_InitStructure);
}

/**
*\*\name    Common_TIM_Base_Initialize.
*\*\param   TIMx :
*\*\          - TIM1
*\*\          - TIM2
*\*\          - TIM3
*\*\          - TIM4
*\*\          - TIM5
*\*\          - TIM6
*\*\param   period
*\*\          - [1, 0xffff]
*\*\param   prescaler
*\*\          - [0, 0xffff]
*\*\return  none
**/
static void _TIM_Base_Initialize(TIM_Module *TIMx, uint16_t period, uint16_t prescaler)
{
    TIM_TimeBaseInitType TIM_TimeBaseStructure;
    TIM_Base_Struct_Initialize(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.Period    = period;
    TIM_TimeBaseStructure.Prescaler = prescaler;
    TIM_TimeBaseStructure.ClkDiv    = 0;
    TIM_TimeBaseStructure.CntMode   = TIM_CNT_MODE_UP;

    TIM_Base_Initialize(TIMx, &TIM_TimeBaseStructure);   
}

/**
*\*\name    Common_TIM_NVIC_Initialize.
*\*\param   IRQ_number :
*\*\          - TIM1_BRK_IRQn
*\*\          - TIM1_UP_IRQn
*\*\          - TIM1_TRG_COM_IRQn
*\*\          - TIM1_CC_IRQn
*\*\          - TIM2_IRQn
*\*\          - TIM3_IRQn
*\*\          - TIM4_IRQn
*\*\          - TIM8_BRK_IRQn
*\*\          - TIM8_UP_IRQn
*\*\          - TIM8_TRG_COM_IRQn
*\*\          - TIM8_CC_IRQn
*\*\          - TIM5_IRQn
*\*\          - TIM6_IRQ
*\*\param   command
*\*\          - ENABLE
*\*\          - DISABLE
*\*\return  none
**/
static void _DPM_TIM_NVIC_Initialize(IRQn_Type IRQ_number, FunctionalState command)
{
    NVIC_InitType NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = IRQ_number;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    
    if(ENABLE == command)
    {
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    }
    else
    {
        NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
    }
    
    NVIC_Initializes(&NVIC_InitStructure);
}


//1 / (32000000 *2 / 100) * 3200 * 1000 = 5 ms 定时周期
static uint32_t _TIM_ForSwInit(void)
{
    uint32_t BSTIM_clock;
    RCC_ClocksType RCC_Clocks;

    RCC_APB1_Peripheral_Clock_Enable(RCC_APB1_PERIPH_TIM6);

    RCC_Clocks_Frequencies_Value_Get(&RCC_Clocks);


    if(RCC_Clocks.HclkFreq > RCC_Clocks.Pclk1Freq) 
    {
        BSTIM_clock = RCC_Clocks.Pclk1Freq * 2; 
    }
    else
    {
        BSTIM_clock = RCC_Clocks.Pclk1Freq;
    }

    _TIM_NVIC_Initialize(TIM6_IRQn, ENABLE);

    /* Time base configuration�? period = 65535, prescaler = prescaler */
    _TIM_Base_Initialize(TIM6, 3200, 100);

    /* NVIC Configuration */
    _DPM_TIM_NVIC_Initialize(TIM6_IRQn, ENABLE);

    TIM_Base_Reload_Mode_Set(TIM6, TIM_PSC_RELOAD_MODE_IMMEDIATE);
    TIM_Interrupt_Enable(TIM6, TIM_INT_UPDATE);
    TIM_On(TIM6);

    return BSTIM_clock;
}



void DPM_LedSwInit(void)
{
    RCC_AHB_Peripheral_Clock_Enable(LED_SW_PERIPH_GPIO);

	/* Define a structure of type GPIO_InitType */
	GPIO_InitType GPIO_InitStructure;
    /* Assign default value to GPIO_InitStructure structure */
    GPIO_Structure_Initialize(&GPIO_InitStructure);
    /* Select the GPIO pin to control */
    GPIO_InitStructure.Pin          = LED_PIN ;
    /* Set pin mode to general push-pull output */
    GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_OUT_PP;
    GPIO_InitStructure.GPIO_Pull   = GPIO_PULL_UP ;
    /* Set the pin drive current to 4MA*/
    GPIO_InitStructure.GPIO_Current = GPIO_DS_4MA;
    /* Initialize GPIO */
    GPIO_Peripheral_Initialize(LED_SW_GPIO, &GPIO_InitStructure);

    GPIO_Structure_Initialize(&GPIO_InitStructure);
    /* Select the GPIO pin to control */
    GPIO_InitStructure.Pin          = SW1_PIN | SW2_PIN | SW3_PIN;
    /* Set pin mode to general push-pull output */
    GPIO_InitStructure.GPIO_Mode    = GPIO_MODE_INPUT;
    GPIO_InitStructure.GPIO_Pull   = GPIO_PULL_UP ;
    /* Initialize GPIO */
    GPIO_Peripheral_Initialize(LED_SW_GPIO, &GPIO_InitStructure);

    //����led�ܽ����
    GPIO_Pins_Set(LED_SW_GPIO, LED_PIN);

    uint32_t freq = _TIM_ForSwInit();
    for(int i = 0; i<3; i++)
    {
        sw_infor_arr[i].current_level = 1;
        sw_infor_arr[i].last_level = 1;
        sw_infor_arr[i].low_count = 0;
        sw_infor_arr[i].long_press_flag = 0;
        sw_infor_arr[i].short_press_flag = 0;
    }
}


void DPM_LedSet(uint8_t state)
{
    if(state)
    {
        GPIO_Pins_Set(LED_SW_GPIO, LED_PIN);
    }
    else
    {
        GPIO_Pins_Reset(LED_SW_GPIO, LED_PIN);
    }
}

static uint8_t _SwRead(uint8_t sw_number)
{
    uint8_t temp;
    if(sw_number>2)
    {
        printf("sw_number error\n");
        return 0;
    }
    switch (sw_number)
    {
    case 0:
        temp = GPIO_Input_Pin_Data_Get(LED_SW_GPIO, SW1_PIN);
        break;
    case 1:
        temp = GPIO_Input_Pin_Data_Get(LED_SW_GPIO, SW2_PIN);
        break;
    case 2:
        temp = GPIO_Input_Pin_Data_Get(LED_SW_GPIO, SW3_PIN);
        break;

    default:
        break;
    }
    return temp;
}


//放在5ms定时器中断中
void DPM_SwScan(void)
{
    for(int i=0; i<3; i++)
    {
        sw_infor_arr[i].last_level = sw_infor_arr[i].current_level;
        sw_infor_arr[i].current_level = _SwRead(i);
        //松手检测
        if((sw_infor_arr[i].current_level != sw_infor_arr[i].last_level) && (sw_infor_arr[i].current_level == 1))
        {
            DPM_LedSet(1);
            if(sw_infor_arr[i].low_count > 140)   //长按1s
            {
                sw_infor_arr[i].low_count = 0;
                sw_infor_arr[i].long_press_flag = 1;
            }
            else if(sw_infor_arr[i].low_count >= 2)   //
            {
                sw_infor_arr[i].low_count = 0;
                sw_infor_arr[i].short_press_flag = 1;
            }
            else   //时间过短，无效检测
            {
                sw_infor_arr[i].low_count = 0;
            }
        }
        //按下检测
        else if(sw_infor_arr[i].current_level == 0)
        {
            DPM_LedSet(0);
            //等待前一次按键标志位被读取执行
            if((sw_infor_arr[i].short_press_flag == 0) && (sw_infor_arr[i].long_press_flag == 0))
            {
               sw_infor_arr[i].low_count++;
            }
        }
    }
}

uint8_t DPM_SwInforRead(void)
{
    uint8_t re = 0;
    for(int i = 0; i<3; i++)
    {
        re |= sw_infor_arr[i].short_press_flag << (i*2);
        sw_infor_arr[i].short_press_flag = 0;
        re |= sw_infor_arr[i].long_press_flag <<(i*2+1);
        sw_infor_arr[i].long_press_flag = 0;
    }
    return re;
}
